package com.zzy.test.emailLogin;

import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author Lucas-zhang
 * @description TODO
 * @date 2022-03-19 14:57
 */
public class EmailCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    // 前端传来的参数名
    private final String SPRING_SECURITY_EMAIL_KEY = "email";
    private final String SPRING_SECURITY_EMAIL_CODE_KEY = "email_code";

    // 自定义的路径匹配器，拦截Url为:/email/login
    private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/email/login",
            "POST");

    // 是否仅POST方式
    private boolean postOnly = true;

    public EmailCodeAuthenticationFilter() {
        super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
    }

    /**
     * 认证方法，在父类的doFilter中调用
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not support : " + request.getMethod());
        }
        System.out.println("email attemptAuthentication");
        // 获取邮箱号码
        String email = obtainEmail(request);
        email = (email != null) ? email : "";
        email = email.trim();
        // 获取邮箱验证码
        String emailCode = obtainEmailCode(request);
        emailCode = (emailCode != null) ? emailCode : "";
        // 构造Token
        EmailCodeAuthenticationToken authRequest = new EmailCodeAuthenticationToken(email, emailCode);
        setDetails(request, authRequest);
        // 使用AuthenticationManager来进行认证
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    /**
     * 获取请求中email参数
     * @param request
     * @return
     */
    @Nullable
    protected String obtainEmail(HttpServletRequest request) {
        return request.getParameter(this.SPRING_SECURITY_EMAIL_KEY);
    }

    /**
     * 获取请求中验证码参数email_code
     * @param request
     * @return
     */
    @Nullable
    protected String obtainEmailCode(HttpServletRequest request) {
        return request.getParameter(this.SPRING_SECURITY_EMAIL_CODE_KEY);
    }

    protected void setDetails(HttpServletRequest request, EmailCodeAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }
}
